// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <memory>
#include <string>
#include <unordered_map>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/deribit_base/api_util/auth_key.h"
#include "coin2/exchange/order/deribit.pb.h"

namespace coin2::exchange::deribit_futures::api_order {

enum DeribitOrderSubTopicId : int { DEPOSIT = 10000, WITHDRAWAL = 10001 };

class DeribitFuturesNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::DeribitFuturesRestParams;
  using AsioHttpContextList = std::list<std::shared_ptr<AsioHttpContext>>;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit DeribitFuturesNativePrivateClient(
      const MarketExchangeApi& mea,
      const order::OrderConnectionConfig& config);

  std::shared_ptr<AsioHttpContext> GenerateOrRefreshAuth();
  std::shared_ptr<AsioHttpContext> QueryAccountBalance();
  std::shared_ptr<AsioHttpContext> QueryAccountSummary(const std::string&);
  std::shared_ptr<AsioHttpContext> QueryAccountPosition(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryHistoryOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTrades(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelOrder(const RestParams& params);

  std::shared_ptr<AsioHttpContext> QueryDeposits(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryWithdrawals(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryTransfers(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;
  std::string GetCurrMilliseconds() const {
    return std::to_string(GetCurrentTimestamp() / 1000000);
  }

  bool has_auth_token() const {
    return local_auth_->has_auth_token() && !local_auth_->get_is_refreshing_token();
  }

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);
  AsioHttpContextList SubmitRestQueryList(const RestQueryProto& query);

  void Prepare() override;
  std::string DebugString() const;

 private:
  std::string auth_path_;
  std::string account_path_;
  std::string position_path_;
  std::string trade_path_;
  std::string open_orders_path_;
  std::string hist_orders_path_;
  std::string place_order_path_buy_;
  std::string place_order_path_sell_;
  std::string place_order_path_;
  std::string cancel_order_path_;
  std::string kind_;  // ie, market type
  std::string deposits_path_;
  std::string withdrawals_path_;
  std::string transfers_path_;

  // handle api limit
  int64_t start_time_{0};
  std::unordered_map<std::string, int32_t> api_block_info_;
  std::unordered_map<std::string, int32_t> api_req_info_;
  std::string auth_token_;
  std::string refresh_token_;
  int64_t last_token_time_{0};
  int64_t expires_in_{0};

  DeribitRestAuth* local_auth_ = nullptr;
};

}  // namespace coin2::exchange::deribit_futures::api_order
